package com.gyx.lottery.service.impl;

import com.gyx.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.gyx.lottery.common.utils.JacksonUtil;
import com.gyx.lottery.common.utils.RedisUtil;
import com.gyx.lottery.controller.param.DrawPrizeParam;
import com.gyx.lottery.controller.param.WinningRecordParam;
import com.gyx.lottery.dao.dataobject.*;
import com.gyx.lottery.dao.mapper.*;
import com.gyx.lottery.service.DrawPrizeService;
import com.gyx.lottery.service.dto.WinningRecordDTO;
import com.gyx.lottery.service.enums.ActicityPrizeTiersEnum;
import com.gyx.lottery.service.enums.ActivityPrizeStatuseEnum;
import com.gyx.lottery.service.enums.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.gyx.lottery.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.gyx.lottery.common.config.DirectRabbitConfig.ROUTING;
@Service
public class DrawPrizeParamImpl implements DrawPrizeService {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    ActivityMapper activityMapper;
    @Autowired
    ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    PrizeMapper prizeMapper;
    @Autowired
    WinningRecordMapper winningRecordMapper;
    @Autowired
    ActivityUserMapper activityUserMapper;
    @Autowired
    RedisUtil redisUtil;
    Logger logger= LoggerFactory.getLogger(DrawPrizeParamImpl.class);
    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;

    @Override
    public void drawPrize(DrawPrizeParam param) {
        //为了优化用户体验，使用rabbit-mq进行异步处理
        //将抽奖的消息先储存在队列中，之后监听的时候再进行处理，后端直接进行返回，
        Map<String,String> map=new HashMap<>();
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeVauleAsString(param));
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
        logger.info("mq发消息成功，发送消息为:{}",JacksonUtil.writeVauleAsString(map));

    }

    @Override
    public boolean checkDrawPrizeParam(DrawPrizeParam param) {
            //校验参数是否为空
        if(param==null)
            {
                logger.warn(ServiceErrorCodeConstants.DRAW_PRIZE_PARAM_EMPTY.getMsg());
                return false;
            }
            //校验活动有效
        ActivityDO activityDO = activityMapper.selectById(param.getActivityId());
        if(activityDO == null){
            logger.warn(ServiceErrorCodeConstants.ACTIVITY_NOT_EXESIST_ERROR.getMsg());
            return false;
        }
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name()))
        {
            logger.warn(ServiceErrorCodeConstants.ACTIVITY_STATUS_ERROR.getMsg());
            return false;
        }
        //校验奖品有效
        ActivityPrizeDO activityPrizeDO=activityPrizeMapper.
                selectByIdAndPrizeId(param.getActivityId(),param.getPrizeId());
        if(activityPrizeDO == null){
            logger.warn(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR.getMsg());
            return false;
        }
        if(!activityPrizeDO.getStatus().
                equalsIgnoreCase(ActivityPrizeStatuseEnum.INIT.name()))
        {
            logger.warn(ServiceErrorCodeConstants.ACTIVITY_PRIZE_STATUS_ERROR.getMsg());
            return false;
        }
        //校验奖品数量与中奖者数量是否一致
        if(activityPrizeDO.getPrizeAmount()!=param.getWinnerList().size()){
            logger.warn(ServiceErrorCodeConstants.ACTIVITY_PRIZE_WINNER_ERROR.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnnerRecords(DrawPrizeParam param) {
            List<Long>userIds=param.getWinnerList().stream()
                    .map(DrawPrizeParam.User::getUserId)
                    .collect(Collectors.toList());
            List<UserDO>userDOList=userMapper.batchSelectByIds(userIds);
            PrizeDO  prizeDO=prizeMapper.selectById(param.getPrizeId());
            ActivityPrizeDO activityPrizeDO=activityPrizeMapper.
                    selectByIdAndPrizeId(param.getActivityId(),param.getPrizeId());
            ActivityDO activityDO=activityMapper.selectById(param.getActivityId());
        List<WinningRecordDO> winningRecordDOList=userDOList.stream()
                .map(userDO -> {
                    WinningRecordDO winningRecordDO=new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDO.getId());
                    winningRecordDO.setActivityName(activityDO.getActivityName());
                    winningRecordDO.setPrizeId(prizeDO.getId());
                    winningRecordDO.setPrizeName(prizeDO.getName());
                    winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDO.setWinnerId(userDO.getId());
                    winningRecordDO.setWinnerName(userDO.getUserName());
                    winningRecordDO.setWinnerEmail(userDO.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());
                    return winningRecordDO;
                }).collect(Collectors.toList());
        winningRecordMapper.batchInsertWinner(winningRecordDOList);
        //从两个角度进行获奖记录的缓存
        //从奖品角度进行缓存
        cacheWinningRecord(param.getActivityId()+"_"+param.getPrizeId(),
                winningRecordDOList,WINNING_RECORDS_TIMEOUT);
        //从活动角度进行缓存
        if(activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            List<WinningRecordDO>allWinner=winningRecordMapper.selectByActivityId(activityDO.getId());
            cacheWinningRecord(String.valueOf(param.getActivityId()),
                    allWinner,WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(activityId == null){
            logger.warn("要删除的活动Id为空");
            return;
        }
        if(prizeId == null){
            logger.warn("要删除的奖品Id为空");
            return;
        }
        winningRecordMapper.delete(activityId,prizeId);
        //清楚奖品角度
        deleteCacheWinningRecords(activityId+"_"+prizeId);
        //清楚活动角度
        deleteCacheWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getWinningRecord(WinningRecordParam param) {
        String key = null == param.getPrizeId()?
                String.valueOf(param.getActivityId()):
                param.getActivityId()+"_"+param.getPrizeId();
        List<WinningRecordDO> winningRecord = getWinningRecordByCache(key);
        if(winningRecord!= null){
            return   convertToWinningRecordDTO(winningRecord);
        }
        List<WinningRecordDO>winningRecordDOList=
                winningRecordMapper.selectByParam(param.getActivityId(),param.getPrizeId());
        cacheWinningRecord(key,winningRecordDOList,WINNING_RECORDS_TIMEOUT);
        return  convertToWinningRecordDTO(winningRecordDOList);
    }

    private List<WinningRecordDTO> convertToWinningRecordDTO
            (List<WinningRecordDO> winningRecord) {
       return  winningRecord.stream()
                .map(winningRecordDO -> {
                    WinningRecordDTO winningRecordDTO=new WinningRecordDTO();
                    winningRecordDTO.setWinnerId(winningRecordDO.getWinnerId());
                    winningRecordDTO.setWinnerName(winningRecordDO.getWinnerName());
                    winningRecordDTO.setPrizeName(winningRecordDO.getPrizeName());
                    winningRecordDTO.setPrizeTier(
                            ActicityPrizeTiersEnum.forName(
                                    winningRecordDO.getPrizeTier()));
                    winningRecordDTO.setWinningTime(winningRecordDO.getWinningTime());
                    return  winningRecordDTO;
                }).collect(Collectors.toList());
    }

    private void deleteCacheWinningRecords(String key){
        if(redisUtil.hasKey(WINNING_RECORDS_PREFIX+key)){
            redisUtil.del(WINNING_RECORDS_PREFIX+key);
        }
        else{
            logger.warn("要删除的key不存在:{}",WINNING_RECORDS_PREFIX+key);
        }
    }

    private void cacheWinningRecord(String key, List<WinningRecordDO> value,
                                    Long timeout) {
        String str="";
        if(!StringUtils.hasText(key)|| CollectionUtils.isEmpty(value))
        {
            logger.warn("key:{},value:{},key或者value为空",key,JacksonUtil.writeVauleAsString(value));
            return;
        }
        try{
            str=WINNING_RECORDS_PREFIX+key;
            redisUtil.set(str,JacksonUtil.writeVauleAsString(value),timeout);
        }
        catch (Exception e){
            logger.warn("key:{},value:{}缓存失败",WINNING_RECORDS_PREFIX+key,value);
        }
    }
    private  List<WinningRecordDO> getWinningRecordByCache(String key){
            if(key == null){
                logger.info("获取中间记录的key值为空");
            }
            String str="";
        try{
            str=WINNING_RECORDS_PREFIX+key;
            String records = redisUtil.get(str);
            if(!StringUtils.hasText(records)){
                logger.info("key的缓存已失效 key:{}",WINNING_RECORDS_PREFIX+key);
                return null;
            }
            List<WinningRecordDO> winningRecordDOList =
                    JacksonUtil.readListValue(records, WinningRecordDO.class);
            return winningRecordDOList;
        }
        catch (Exception e){
            logger.warn("key:{},value:{}获取缓存失败",WINNING_RECORDS_PREFIX+key,redisUtil.get(str));
            return null;
        }

    }
}
